package com.tanhua.server.service;

import com.alibaba.fastjson.JSON;
import com.tanhua.commons.exception.TanHuaException;
import com.tanhua.commons.templates.FaceTemplate;
import com.tanhua.commons.templates.HuanXinTemplate;
import com.tanhua.commons.templates.OssTemplate;
import com.tanhua.commons.templates.SmsTemplate;
import com.tanhua.domain.db.User;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.vo.ErrorResult;
import com.tanhua.domain.vo.UserInfoVo;
import com.tanhua.dubbo.api.UserApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.server.interceptor.UserHolder;
import com.tanhua.server.utils.GetAgeUtil;
import com.tanhua.server.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static jdk.nashorn.internal.runtime.regexp.joni.Config.log;

/**
 * @Classname UserService
 * @Description TODO 消费层业务处理
 * @Date 2021/3/6 18:13
 * @Created by gan
 */
@Service
@Slf4j
public class UserService {
    @Reference
    private UserApi userApi;

    @Reference
    private UserInfoApi userInfoApi;

    @Autowired
    private FaceTemplate faceTemplate;

    @Autowired
    private SmsTemplate smsTemplate;

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @Value("${tanhua.redisValidateCodeKeyPrefix}")
    private String redisValidateCodeKeyPrefix;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private JwtUtils jwtUtils;



   /* //添加用户
    public ResponseEntity saveUser(String mobile, String password) {
        User user=new User();
        user.setMobile(mobile);
        user.setPassword(password);
        userApi.save(user);

        return ResponseEntity.ok(null);
    }

    //根据手机号码查询
    public ResponseEntity findByMobile(String mobile) {
        User user = userApi.findByMobile(mobile);

        return ResponseEntity.ok(user);
    }*/


    //发送验证码
    public void sendValidateCode(String phone) {
        //1. 构建redis中验证的key
        String key = redisValidateCodeKeyPrefix + phone;
        //2. 获取redis中验证码
        String codeInRedis = (String)redisTemplate.opsForValue().get(key);
        log.info("codeInRedis:{}",codeInRedis);

        if(StringUtils.isNotEmpty(codeInRedis)) {
            //3. 有值
            //  3.1 返回验证码未失效，抛出自定义异常
            throw new TanHuaException(ErrorResult.duplicate());
        }else {
            //4. 没有
            //5. 生成验证码
            //String validateCode = RandomStringUtils.randomNumeric(6);
            String validateCode = "123456";//RandomStringUtils.randomNumeric(6);
            log.info("=============验证码:{},{}",phone, validateCode);
           /* //6. 发送验证码
            Map<String, String> smsRs = smsTemplate.sendValidateCode(phone,validateCode);
            if(null != smsRs){
                // 验证码发送失败，报错
                throw new TanHuaException(ErrorResult.fail());
            }*/
            //7. 存入redis
            redisTemplate.opsForValue().set(key,validateCode, Duration.ofMinutes(10));
        }
    }

    /**
     * 登陆或注册
     * @param phone
     * @param verificationCode
     * @return
     */
    public Map<String,Object> loginVerification(String phone, String verificationCode) {
        // redis中存入验证码的key
        String key = redisValidateCodeKeyPrefix + phone;
        // redis中的验证码
        String codeInRedis = redisTemplate.opsForValue().get(key);

        log.debug("========== 校验 验证码:{},{},{}",phone,codeInRedis,verificationCode);
        if(StringUtils.isEmpty(codeInRedis)){
            throw new TanHuaException(ErrorResult.loginError());
        }
        if(!codeInRedis.equals(verificationCode)){
            throw new TanHuaException(ErrorResult.validateCodeError());
        }
        redisTemplate.delete(key);// 防止重复提交
        // 查看用户是否存在
        User user = userApi.findByMobile(phone);
        boolean isNew = false;
        if(null == user){
            // 不存在则添加用户
            user = new User();
            user.setMobile(phone);
            // 手机号后6位为默认密码
            user.setPassword(DigestUtils.md5Hex(phone.substring(phone.length()-6)));
            log.info("============== 添加新用户 {}", phone);
            Long userId = userApi.save(user);
            user.setId(userId);
            isNew = true;
            //注册环信通讯
            huanXinTemplate.register(user.getId());
        }
        // 签发token令牌
        String token = jwtUtils.createJWT(phone,user.getId());
        // 用户信息存入redis，方便后期获取，有效期为1天
        String userString = JSON.toJSONString(user);
        redisTemplate.opsForValue().set("TOKEN_" + token,userString,1, TimeUnit.DAYS);
        log.debug("=========== 签发token: {}", token);
        // 返回结果
        Map<String,Object> resultMap = new HashMap<String,Object>();
        resultMap.put("isNew",isNew);
        resultMap.put("token",token);
        return resultMap;
    }

    /**
     * 通过token获取登陆用户信息
     * @param token
     * @return
     */
    public User getUserByToken(String token){
        String key = "TOKEN_" + token;
        String userJsonStr = redisTemplate.opsForValue().get(key);
        if(StringUtils.isEmpty(userJsonStr)){
            return null;
        }
        // 延长有效期，续期
        redisTemplate.expire(key,1, TimeUnit.DAYS);
        User user = JSON.parseObject(userJsonStr, User.class);
        return user;
    }


    /**
     * 完善用户信息
     * @param userInfo
     * @param token
     */
    public void saveUserInfo(UserInfo userInfo, String token) {
       /* User user = getUserByToken(token);
        if(null == user){
            throw new TanHuaException("登陆超时，请重新登陆");
        }*/
        userInfo.setId(UserHolder.getUserId());
        //获取年龄
        userInfo.setAge(GetAgeUtil.getAge(userInfo.getBirthday()));
        //添加
        userInfoApi.save(userInfo);
    }


    //上传用户头像处理
    public void updateUserAvatar(MultipartFile headPhoto, String token) {
       /* User user = getUserByToken(token);
        if(null == user){
            throw new TanHuaException("登陆超时，请重新登陆");
        }*/
        try {
            String filename = headPhoto.getOriginalFilename();
            byte[] bytes = headPhoto.getBytes();
            // 人脸检测
            if(!faceTemplate.detect(bytes)){
                throw new TanHuaException("没有检测到人脸，请重新上传");
            }
            // 上传头像到阿里云Oss
            String avatar = ossTemplate.upload(filename, headPhoto.getInputStream());
            UserInfo userInfo = new UserInfo();
            userInfo.setId(UserHolder.getUserId());
            userInfo.setAvatar(avatar);
            // 更新用户头像
            userInfoApi.update(userInfo);
        } catch (IOException e) {
            //e.printStackTrace();
            log.error("上传头像失败",e);
            throw new TanHuaException("上传头像失败，请稍后重试");
        }
    }


    /**
     * 通过id查询用户基本信息
     * @param userId
     * @return
     */
    public UserInfoVo findUserInfoById(Long userId) {
        UserInfo userInfo = userInfoApi.findById(userId);
        UserInfoVo vo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, vo);
        // 年龄字段，数据库存的是数值，而页面需要的是字符串。
        if(null != userInfo.getAge()){
            vo.setAge(String.valueOf(userInfo.getAge().intValue()));
        }
        return vo;
    }


    /**
     * 保存用户基本信息
     * @param vo
     * @param token
     */
    public void updateUserInfo(UserInfoVo vo, String token) {

       /* User user = getUserByToken(token);
        if(null == user){
            throw new TanHuaException("登陆超时，请重新登陆");
        }*/
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(vo,userInfo);
        // 通过birthday，计算用户的年龄
        int age = GetAgeUtil.getAge(userInfo.getBirthday());
        userInfo.setAge(age);//设置年龄
        userInfo.setId(UserHolder.getUserId());
        userInfoApi.update(userInfo);
    }


    /**
     * 更新用户头像
     */
    public void header(String token, MultipartFile headPhoto) {
        log.info("更新用户头像{},token{}",headPhoto.getOriginalFilename(),token);
        try {
            //1.基于token获取用户信息
            String userStr = redisTemplate.opsForValue().get("TOKEN_" + token);
            if(StringUtils.isEmpty(userStr)){
                throw new TanHuaException("登陆超时，请重新登陆");
            }
            User user = JSON.parseObject(userStr, User.class);
            Long userId = user.getId();
            //2.查询用户信息（后续用于删除头像）
            UserInfo userInfo = userInfoApi.findByUserId(userId);
            //更新头像之前的头像
            String oldAvatar = userInfo.getAvatar();
            //3.人脸识别
            boolean detect = faceTemplate.detect(headPhoto.getBytes());
            if(!detect){
                throw new TanHuaException("没有检测到人脸，请重新上传");
            }
            log.info("人脸识别成功了....");

            //4.上传头像
            String filename = headPhoto.getOriginalFilename();
            String avatar = ossTemplate.upload(filename, headPhoto.getInputStream());
            log.info("图片上传成功了....");

            //5.更新用户头像
            userInfo  = new UserInfo();//更新头像
            userInfo.setAvatar(avatar);//头像
            userInfo.setId(userId);
            userInfoApi.update(userInfo);
            log.info("更新用户头像成功了....");
            //6.删除头像
            ossTemplate.deleteFile(oldAvatar);
            log.info("删除阿里云头像成功了....");
        } catch (IOException e) {
            e.printStackTrace();
            throw new TanHuaException("更新头像失败，请稍后重试");
        }
    }
}
